package com.xinruke.hostels.manage.user.service.impl;

import com.xinruke.hostels.common.cache.ManageUserCache;
import com.xinruke.hostels.common.cache.vo.LoginManageResultVO;
import com.xinruke.hostels.common.exception.ArgumentException;
import com.xinruke.hostels.common.po.*;
import com.xinruke.hostels.common.util.UUIDUtil;
import com.xinruke.hostels.common.vo.ErrorEnum;
import com.xinruke.hostels.common.vo.ResultVO;
import com.xinruke.hostels.manage.user.interfaces.dto.*;
import com.xinruke.hostels.manage.user.mapper.*;
import com.xinruke.hostels.manage.user.service.RightService;
import com.xinruke.hostels.manage.user.service.RoleService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.Sqls;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author GuoZheng
 * @ClassName RightServiceImpl
 * @date：2019/6/15
 * @version: V1.0.0
 * @description：
 */
@Service
public class RightServiceImpl implements RightService {
    @Resource
    private XtYonghucaidanGuanxiMapper xtYonghucaidanGuanxiMapper;

    @Resource
    private XtYonghujueseGuanxiMapper xtYonghujueseGuanxiMapper;

    @Resource
    private XtJuesecaidanGuanxiMapper xtJuesecaidanGuanxiMapper;

    @Resource
    private XtCaidanAnniuMapper xtCaidanAnniuMapper;

    @Resource
    private XtCaidanMapper xtCaidanMapper;

    @Resource
    private RoleService roleService;

    @Resource
    private ManageUserCache manageUserCache;

    /**
     * 1.在角色菜单关系表中查询角色对应的菜单id和逗号隔开的button字符串，
     * 2.转化菜单id和button集合为map
     * 3.通过map去查询详情，填充所属button集的List字段，填充菜单基本信息字段。且存在下级菜单的字段(暂时为空字段）
     * 4.一次循环，对所有菜单寻找parentId是否存在，存在的话，组装进去。上级菜单不存在话添加到返回集中。即返回集只存储关系表中相对最高级别的菜单
     *
     * @param rightsQueryByRoleIdDTO
     * @return
     */
    @Override
    public List<RoleRightsQueryResultDTO> getRightsListByRoleId(RoleRightsQueryDTO rightsQueryByRoleIdDTO) {
        //得到角色和菜单关系集合
        List<XtJuesecaidanGuanxi> relations = xtJuesecaidanGuanxiMapper.selectByExample(Example.builder(XtJuesecaidanGuanxi.class)
                .where(Sqls.custom()
                        .andEqualTo("shanchubiaoshi", XtJuesecaidanGuanxi.SHANCHUBIAOSHI_WU_XIOA)
                        .andEqualTo("jueseId", rightsQueryByRoleIdDTO.getRoleId())
                ).build());

        if (CollectionUtils.isEmpty(relations)) {
            return Collections.EMPTY_LIST;
        }
        return relations.stream().map(r -> {
            List<MenusAndButtonsDto> buttonDtoList = getButtonList(r.getCaidanId(), r.getAnniulist());
            return new RoleRightsQueryResultDTO(r.getCaidanId(), buttonDtoList);
        }).collect(Collectors.toList());
    }

    /**
     * 通过button字符串拼接得到ButtonDtoList
     *
     * @param caidanId
     * @param anniulist
     * @return
     */
    @Override
    public List<MenusAndButtonsDto> getButtonList(Integer caidanId, String anniulist) {
        if (StringUtils.isEmpty(anniulist)) {
            return Collections.EMPTY_LIST;
        }
        List<String> buttonTypeList = Arrays.stream(anniulist.split(",")).collect(Collectors.toList());
        List<XtCaidanAnniu> buttonList = xtCaidanAnniuMapper.selectByExample(Example.builder(XtCaidanAnniu.class).where(Sqls.custom().andEqualTo("caidanId", caidanId).andIn("leibie", buttonTypeList)).build());

        return buttonList.stream().map(b -> {
            MenusAndButtonsDto buttonDto = new MenusAndButtonsDto();
            BeanUtils.copyProperties(b, buttonDto);
            buttonDto.setType(MenusAndButtonsDto.ANNIULEIXNG);
            buttonDto.setFucaidanId(caidanId.toString());
            return buttonDto;
        }).collect(Collectors.toList());
    }

    /**
     * 1.在用户菜单关系表中查询用户对应的菜单id和逗号隔开的button字符串，
     * 2.在角色菜单关系表中查询角色对应的菜单id和逗号隔开的button字符串，
     * 3.合并为只有菜单id和buttonid集的map并去重,去重规则：优先使用用户菜单关系表内容
     * 4.填充菜单和按钮基础信息并组装上下级结构
     *
     * @param rightsQueryUserIdDTO
     * @return
     */
    @Override
    public ResultVO<List<MenusAndButtonsDto>> getRightsListByUserId(UserRightsQueryDTO rightsQueryUserIdDTO) {
        ResultVO<List<MenusAndButtonsDto>> resultVO = ResultVO.fail();
        LoginManageResultVO cuurentUserInfo = manageUserCache.getLoginManageUserInfo();
        //如果是超管用户直接返回权限树
        if (cuurentUserInfo.getYonghuleixing() == XtYewuyonghu.YONGHULEIXNG_CHANOGUAN) {
            RightsQueryDTO rightsQueryDTO = new RightsQueryDTO();
            rightsQueryDTO.setSuoshuxitong(cuurentUserInfo.getSuoshuxitong());
            List<MenusAndButtonsDto> menusAndButtonsDtos = rightsTree(rightsQueryDTO);
            resultVO = ResultVO.success();
            resultVO.setData(menusAndButtonsDtos);
            return resultVO;
        }
        Integer userId = cuurentUserInfo.getId();
        //得到用户菜单关系表中的菜单权限
        List<XtYonghucaidanGuanxi> xtYonghucaidanGuanxis = xtYonghucaidanGuanxiMapper.selectByExample(Example.builder(XtYonghucaidanGuanxi.class)
                .where(Sqls.custom()
                        .andEqualTo("shanchubiaoshi", XtYonghucaidanGuanxi.SHANCHUBIAOSHI_WU_XIOA)
                        .andEqualTo("yewuyonghuId", userId)
                ).build());


        //得到对应角色的菜单权限
        List<XtYonghujueseGuanxi> xtYonghujueseGuanxis = xtYonghujueseGuanxiMapper.selectByExample(Example.builder(XtYonghujueseGuanxi.class)
                .where(Sqls.custom()
                        .andEqualTo("shanchubiaoshi", XtYonghujueseGuanxi.SHANCHUBIAOSHI_WU_XIOA)
                        .andEqualTo("yewuyonghuId", userId)
                ).build());
        List<Integer> roleIds = xtYonghujueseGuanxis.stream().map(XtYonghujueseGuanxi::getJueseId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(roleIds)) {
            resultVO.setCode(ErrorEnum.ERROR_212.getCode());
            resultVO.setMessage(ErrorEnum.ERROR_212.getMsg());
            return resultVO;
        }
        List<XtJuesecaidanGuanxi> rightRelationsByRoleIds = roleService.getRightRelationsByRoleIds(roleIds);

        //得到用户菜单关系表中菜单id和对应按钮集string的map
        Map<Integer, String> userMenusAndButtonMaps = xtYonghucaidanGuanxis.stream().collect(Collectors.toMap(XtYonghucaidanGuanxi::getCaidanId, XtYonghucaidanGuanxi::getAnniulist));

        //得到角色菜单关系表中菜单id和对应按钮集string的map。当多个角色有重复的菜单权限，进行去重合并
        Map<Integer, String> roleMenusAndButtonMaps = rightRelationsByRoleIds.stream().collect(Collectors.groupingBy(XtJuesecaidanGuanxi::getCaidanId))
                //根据菜单分组，找到重复的菜单集合
                .entrySet()
                .stream()
                //将重复菜单对应的按钮集进行去重合并。
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream()
                        .flatMap(guanxi -> Arrays.stream(guanxi.getAnniulist().split(",")))
                        .distinct()
                        .reduce((a, b) -> a + "," + b)
                        .orElse("")));


        //去重后合并为map,去重规则：优先使用用户菜单关系表内容
        userMenusAndButtonMaps.keySet().forEach(u -> {
            if (roleMenusAndButtonMaps.keySet().contains(u)) {
                roleMenusAndButtonMaps.remove(u);
            }
        });
        userMenusAndButtonMaps.putAll(roleMenusAndButtonMaps);

        //填充菜单按钮信息，组装菜单结构
        List<MenusAndButtonsDto> menusAndButtonsDtoList = packageMenusAndButtonsInfos(userMenusAndButtonMaps, rightsQueryUserIdDTO.getSuoshuxitong());
        resultVO = ResultVO.success();
        resultVO.setData(menusAndButtonsDtoList);
        return resultVO;
    }

    /**
     * 1.填充按钮集合和菜单的字段信息
     * 2.组装菜单树结构
     *
     * @return
     */
    public List<MenusAndButtonsDto> packageMenusAndButtonsInfos(Map<Integer, String> menusAndButtonMaps, Byte suoshuxitong) {
        List<MenusAndButtonsDto> menusDTOList = new ArrayList<>();
        List<MenusAndButtonsDto> resultDTOList = new ArrayList<>();

        //1.填充按钮集合和菜单的字段信息
        List<XtCaidan> xtCaidans = xtCaidanMapper.selectByExample(Example.builder(XtCaidan.class)
                .where(Sqls.custom()
                        .andEqualTo("shanchubiaoshi", XtCaidan.SHANCHUBIAOSHI_WU_XIOA)
                        .andIn("id", menusAndButtonMaps.keySet())
                ).build()
        );
        xtCaidans.stream().filter(c -> c.getSuoshuxitong().equals(suoshuxitong)).forEach(caidan -> {
            MenusAndButtonsDto menuDto = new MenusAndButtonsDto();
            String value = menusAndButtonMaps.get(caidan.getId());
            BeanUtils.copyProperties(caidan, menuDto);
            menuDto.setId(caidan.getId().toString());//菜单的id需要转为string
            menuDto.setMingcheng(caidan.getCaidanmingcheng());
            menuDto.setType(MenusAndButtonsDto.CAIDANLEIXNG);
            //组装按钮集类型
            menuDto.setButtonTypeList(Arrays.stream(value.split(",")).collect(Collectors.toList()));
            //通过button字符串拼接得到ButtonDtoList
            menuDto.getSubMenusAndButtonsList().addAll(getButtonList(caidan.getId(), value));
            menuDto.setFucaidanId(caidan.getFucaidanId().toString());

            menusDTOList.add(menuDto);
        });

        menusAndButtonMaps.forEach((key, value) -> {
        });

        RightsQueryDTO rightsQueryDTO = new RightsQueryDTO();
        rightsQueryDTO.setSuoshuxitong(Integer.parseInt(suoshuxitong.toString()));
        List<MenusAndButtonsDto> menusAndButtonsDtos = rightsTree(rightsQueryDTO);

        //2.组装菜单树结构
        menusAndButtonsDtos.forEach(menuDto -> {
            List<MenusAndButtonsDto> subList = new ArrayList<>();
            //查找是否存在子菜单
            menusDTOList.stream().filter(menus -> menus.getFucaidanId().equals(menuDto.getId())).forEach(menu -> {
                subList.add(menu);
            });
            menuDto.getSubMenusAndButtonsList().clear();
            menuDto.getSubMenusAndButtonsList().addAll(subList);

            if (!CollectionUtils.isEmpty(subList)) {
                resultDTOList.add(menuDto);
            }

        });
        menusDTOList.stream().filter(menus -> menus.getFucaidanId().equals("1")).forEach(menu -> {
            resultDTOList.add(menu);
        });
        return resultDTOList;

    }

    /**
     * 组装权限列表
     *
     * @param rightsQueryDTO
     * @return
     */
    @Override
    public List<MenusAndButtonsDto> rightsTree(RightsQueryDTO rightsQueryDTO) {

        List<XtCaidan> subMenus = xtCaidanMapper.selectByExample(Example.builder(XtCaidan.class).where(
                Sqls.custom()
                        .andEqualTo("fucaidanId", 1)
                        .andEqualTo("suoshuxitong", rightsQueryDTO.getSuoshuxitong())
                        .andEqualTo("shanchubiaoshi", XtCaidan.SHANCHUBIAOSHI_WU_XIOA)).build());
        //得到所有按钮集合
        List<XtCaidanAnniu> xtCaidanAnniuList = xtCaidanAnniuMapper.selectAll();

        //递归查询
        return getSubMenusAndButtons(subMenus, xtCaidanAnniuList);
    }

    @Override
    @Transactional
    public int assign(RightAssignDto rightsQueryDTO) {
        List<XtJuesecaidanGuanxi> xtJuesecaidanGuanxiList = new ArrayList<>();

        //递归组装po对象
        rightsQueryDTO.getRoleAndMenusDTOList().forEach(r -> {
            XtJuesecaidanGuanxi xtJuesecaidanGuanxi = new XtJuesecaidanGuanxi();
            BeanUtils.copyProperties(r, xtJuesecaidanGuanxi);
            xtJuesecaidanGuanxi.setShanchubiaoshi(XtJuesecaidanGuanxi.SHANCHUBIAOSHI_WU_XIOA);
            xtJuesecaidanGuanxiList.add(xtJuesecaidanGuanxi);
        });
        if (CollectionUtils.isEmpty(xtJuesecaidanGuanxiList)) {
            return 0;
        }
        Integer jueseId = rightsQueryDTO.getRoleAndMenusDTOList().get(0).getJueseId();

        xtJuesecaidanGuanxiMapper.deleteByRoleId(jueseId);

        return xtJuesecaidanGuanxiMapper.insertList(xtJuesecaidanGuanxiList);
    }

    @Override
    public ResultVO addButtonList(List<ButtonListQueryDTO> buttonListQueryDTO) {
        buttonListQueryDTO.forEach(b -> {
            Integer caidanId = getCaidanId(b);
            //删除现有的所有按钮
            xtCaidanAnniuMapper.deleteByExample(Example.builder(XtCaidanAnniu.class).where(Sqls.custom().andEqualTo("caidanId", caidanId)).build());

            List<String> leibie = Arrays.stream(b.getLeibie().split(",")).collect(Collectors.toList());
            leibie.forEach(l -> {
                String[] split = l.split("-");
                XtCaidanAnniu xtCaidanAnniu = new XtCaidanAnniu();
                xtCaidanAnniu.setCaidanId(caidanId);
                xtCaidanAnniu.setLeibie(split[0]);
                xtCaidanAnniu.setMingcheng(split[1]);
                xtCaidanAnniu.setId(UUIDUtil.getUUID());
                xtCaidanAnniuMapper.insertSelective(xtCaidanAnniu);
            });
        });

        return ResultVO.success();
    }

    private Integer getCaidanId(ButtonListQueryDTO b) {
        XtCaidan xtCaidan = xtCaidanMapper.selectOneByExample(Example.builder(XtCaidan.class)
                .where(Sqls.custom()
                        .andEqualTo("caidanbianma", b.getCaidanbianma())
                        .andEqualTo("shanchubiaoshi", 0)
                        .andEqualTo("suoshuxitong", b.getSuoshuxitong())
                ).build());

        if (xtCaidan != null) {
            return xtCaidan.getId();
        }
        XtCaidan insert = new XtCaidan();
        BeanUtils.copyProperties(b, insert);
        //set父菜单id
        if (b.getFucaidanBianMa() != null) {
            XtCaidan fucaidan = xtCaidanMapper.selectOneByExample(Example.builder(XtCaidan.class)
                    .where(Sqls.custom()
                            .andEqualTo("caidanbianma", b.getFucaidanBianMa())
                            .andEqualTo("shanchubiaoshi", 0)
                    ).build());
            insert.setFucaidanId(fucaidan.getId());
        } else {
            //默认一级菜单
            insert.setFucaidanId(1);
            insert.setShanchubiaoshi(XtCaidan.SHANCHUBIAOSHI_WU_XIOA);
            insert.setChuangjianshijian(new Date());
        }
        int i = xtCaidanMapper.insertSelective(insert);
        if (i < 1) {
            throw new ArgumentException("添加菜单错误");
        }
        return insert.getId();
    }


    private List<MenusAndButtonsDto> getSubMenusAndButtons(List<XtCaidan> menus, List<XtCaidanAnniu> xtCaidanAnniuList) {
        List<MenusAndButtonsDto> resultDTOList = new ArrayList<>();
        menus.forEach(m -> {
                    MenusAndButtonsDto parentMenuDto = new MenusAndButtonsDto();
                    BeanUtils.copyProperties(m, parentMenuDto);
                    parentMenuDto.setMingcheng(m.getCaidanmingcheng());
                    parentMenuDto.setType(MenusAndButtonsDto.CAIDANLEIXNG);
                    parentMenuDto.setId(m.getId().toString());//菜单的id需要转为string
                    //添加按钮集
                    List<XtCaidanAnniu> anniuList = xtCaidanAnniuList.stream().filter(anniu -> anniu.getCaidanId().equals(m.getId())).collect(Collectors.toList());
                    List<String> buttonTypeList = anniuList.stream().flatMap(anniu -> Arrays.stream(anniu.getLeibie().split(","))).collect(Collectors.toList());
                    //添加按钮类型list
                    parentMenuDto.setButtonTypeList(buttonTypeList);

                    List<MenusAndButtonsDto> buttonsDtoList = anniuList.stream().map(b -> {
                        MenusAndButtonsDto buttonDto = new MenusAndButtonsDto();
                        BeanUtils.copyProperties(b, buttonDto);
                        buttonDto.setType(MenusAndButtonsDto.ANNIULEIXNG);
                        buttonDto.setFucaidanId(m.getId().toString());
                        return buttonDto;
                    }).collect(Collectors.toList());
                    parentMenuDto.getSubMenusAndButtonsList().addAll(buttonsDtoList);
                    List<XtCaidan> subMenus = xtCaidanMapper.selectByExample(Example.builder(XtCaidan.class).where(Sqls.custom().andEqualTo("fucaidanId", m.getId()).andEqualTo("shanchubiaoshi", XtCaidan.SHANCHUBIAOSHI_WU_XIOA)).build());
                    // 递归组装子菜单
                    if (!CollectionUtils.isEmpty(subMenus)) {
                        parentMenuDto.getSubMenusAndButtonsList().addAll((getSubMenusAndButtons(subMenus, xtCaidanAnniuList)));
                    }
                    resultDTOList.add(parentMenuDto);
                }
        );
        //排序
        return resultDTOList.stream().sorted(Comparator.comparing(MenusAndButtonsDto::getZhanshishunxu)).collect(Collectors.toList());
    }


}
